ci(security): add CodeQL SAST + literal Dockerfile digests (close 7 Scorecard alerts)#431
Conversation
…iterally Two follow-ups on the post-merge OSSF Scorecard surface (PR #430 closed the postcss vuln + ~50 pinning alerts; this closes the SAST finding + the 6 remaining containerImage alerts). CodeQL (#71): add .github/workflows/codeql.yml — GitHub first-party SAST on push/PR to main + weekly, scanning python + javascript-typescript with build-mode none. Closes the Scorecard "SAST tool is not run on all commits" finding and surfaces real code-level bugs on every PR. Action refs pinned to SHAs to match the repo's pinning posture. Dockerfile digests (#59/#60/#80-#83): revert the BASE_IMAGE ARG indirection back to literal `image@sha256:…` on each FROM. The pin was always real, but Scorecard's static parser only credits a digest it can see inline — an ARG-indirected digest reads as "unpinned", which is what kept all 6 containerImage alerts open (Dockerfile:24/46/79 + ui/Dockerfile:24/30/39, confirmed from the Scorecard SARIF locations). Writing tag+digest together also removes the override footgun Gemini flagged on PR #430; Dependabot bumps every FROM occurrence in lockstep, so the repeated node digest is not a sync hazard. Both Dockerfiles pass `docker buildx build --check`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
There was a problem hiding this comment.
Code Review
This pull request replaces ARG-indirected base image digests with inline, literal digest-pinned images in both Dockerfile and ui/Dockerfile to ensure static analysis tools like OSSF Scorecard recognize the pinned dependencies. The review feedback suggests optimizing the multi-stage build in ui/Dockerfile by having the builder stage inherit directly from the deps stage, which avoids redundant setup steps and reduces duplication of the base image digest.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| FROM node:26-bookworm-slim@sha256:79723b41edbedf595f62e943a9f8b0ba9af5b1e61045c5f8f59c2c02c1212a16 AS builder | ||
| WORKDIR /app | ||
| RUN npm install -g pnpm@9 | ||
| COPY --from=deps /app/node_modules ./node_modules |
There was a problem hiding this comment.
Instead of starting the builder stage from the base image and repeating the setup steps (installing pnpm, setting the working directory, and copying node_modules), you can inherit directly from the deps stage. This avoids redundant network requests/installations and reduces the duplication of the base image digest.
FROM deps AS builder
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Accept Gemini's finding on PR #431: have the ui builder stage `FROM deps` instead of re-deriving from the base image. deps already has pnpm, WORKDIR, and node_modules, so this drops a redundant `npm install -g pnpm@9` + the node_modules COPY, removes one base-image digest occurrence, and eliminates one of the two npmCommand Scorecard findings. A stage ref to a digest-pinned stage is still credited as pinned by Scorecard. node_modules is .dockerignore'd so `COPY . .` doesn't clobber the installed deps. Verified with a full `docker buildx build` of the ui image (next build + runner copy succeed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
Gemini Code Assist adjudicationOne finding, accepted and fixed in
CodeQL (python + javascript-typescript) and both |
…n false positives (#432) * fix(security): use execFileSync in gen-types + document path-injection FP Address the 3 CodeQL findings from the first scan of main (PR #431 enabled CodeQL): - gen-types.mjs (medium, js/shell-command-injection-from-environment): the OPENAPI_URL env var was interpolated into an execSync shell string. Switch to execFileSync with an args array — no shell, nothing to inject into. It's a local dev script (CI never runs it) so the real risk was low, but this is the correct pattern regardless. node --check + eslint + prettier clean. - config_repos.py (high ×2, py/path-injection): false positives. `auth_ref` is constrained to `^[a-zA-Z0-9_-]+$` by CreateConfigRepoRequest (no slashes/dots → no traversal at the API boundary) AND _auth_ref_exists has a resolve()+relative_to() containment guard. CodeQL doesn't model the Pydantic pattern or recognize relative_to() as a sanitizer. Added a comment explaining the two guards; the alerts are dismissed as reviewed false positives. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai> * fix(security): resolve npx.cmd on Windows in gen-types (Gemini #432) Accept Gemini's finding: execFileSync('npx', …) ENOENTs on Windows because the launcher is npx.cmd and there's no shell to resolve the extension. Pick the platform-correct executable name. Preserves the no-shell args-array form (the shell-injection fix); just restores the cross-platform parity the original execSync had. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai> --------- Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to #430. That PR closed the postcss vulnerability and ~50 pinning alerts; this one closes the remaining genuinely-actionable Scorecard findings — the SAST alert and the 6
containerImagealerts.CodeQL SAST (#71)
Adds
.github/workflows/codeql.yml— GitHub's first-party static analysis on push/PR tomain+ weekly, scanning python and javascript-typescript (build-mode: none, no compile/service-containers needed). Closes the Scorecard "SAST tool is not run on all commits" finding and, more usefully, runs real static analysis on every PR going forward. Action refs are SHA-pinned to match the repo's pinning posture.Literal Dockerfile digests (#59 / #60 / #80–#83)
Reverts the
BASE_IMAGEARG indirection from #430 back to literalimage@sha256:…on eachFROM. The pin was always real, but Scorecard's static parser only credits a digest it can see inline — an ARG-indirected digest reads as "unpinned", which is exactly what kept all 6containerImagealerts open. Confirmed from the Scorecard SARIF locations:Dockerfile:24/46/79+ui/Dockerfile:24/30/39.Writing tag+digest together on the line also removes the override footgun Gemini flagged on #430, and Dependabot bumps every
FROM …@sha256occurrence in lockstep — so the repeated node digest is not the sync hazard the DRY refactor was trying to avoid.What's intentionally left (intrinsic / impractical)
npmCommand(npm install -g pnpm@9),pipCommand(docs-sitepip install), and the Tier-3 findings (branch protection — relaxed on purpose, solo-dev code-review ratio, project age, fuzzing, OpenSSF badge).Verification
docker buildx build --checkon both Dockerfiles ✓ (no warnings, no${BASE_IMAGE}residue)codeql.ymlYAML parses ✓ ·reuse lintcompliant (1726/1726) ✓not-configured(no advanced/default conflict)🤖 Generated with Claude Code